package com.ma.implatform.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ma.common.enums.IMTerminalType;
import com.ma.common.utils.JwtUtil;
import com.ma.imclient.IMClient;
import com.ma.implatform.config.props.JwtProperties;
import com.ma.implatform.dto.LoginDTO;
import com.ma.implatform.dto.ModifyPwdDTO;
import com.ma.implatform.dto.RegisterDTO;
import com.ma.implatform.entity.User;
import com.ma.implatform.enums.ResultCode;
import com.ma.implatform.exception.GlobalException;
import com.ma.implatform.mapper.UserMapper;
import com.ma.implatform.service.UserService;
import com.ma.implatform.session.SessionContext;
import com.ma.implatform.session.UserSession;
import com.ma.implatform.utils.BeanUtils;
//import com.ma.implatform.utils.SensitiveFilterUtil;
import com.ma.implatform.vo.LoginVO;
import com.ma.implatform.vo.OnlineTerminalVO;
import com.ma.implatform.vo.UserVO;
import io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final JwtProperties jwtProperties;
    private final PasswordEncoder passwordEncoder;
    private final IMClient imClient;
    //private final SensitiveFilterUtil sensitiveFilterUtil;
    @Override
    public LoginVO login(LoginDTO dto) {
        User user = this.findUserByUserName(dto.getUserName());
        if (Objects.isNull(user)){
            throw new GlobalException("用户不存在");
        }
        if (user.getIsBanned()){
            String tip = String.format("您的账号因'%s'已被管理员封禁，请联系客服！",user.getReason());
            throw new GlobalException(tip);
        }
        if (!passwordEncoder.matches(dto.getPassword(), user.getPassword())) {
            throw new GlobalException(ResultCode.PASSWOR_ERROR);
        }
        //生成token
        UserSession session = BeanUtils.copyProperties(user, UserSession.class);
        session.setUserId(user.getId());
        session.setTerminal(dto.getTerminal());
        String strJson = JSON.toJSONString(session);
        String accessToken = JwtUtil.sign(user.getId(), strJson, jwtProperties.getAccessTokenExpireIn(),jwtProperties.getAccessTokenSecret());
        String refreshToken = JwtUtil.sign(user.getId(),strJson,jwtProperties.getRefresTokenExpireIn(),jwtProperties.getRefreshTokenSecret());

        LoginVO loginVO = new LoginVO();
        loginVO.setAccessToken(accessToken);
        loginVO.setAccessTokenExpiresIn(jwtProperties.getAccessTokenExpireIn());
        loginVO.setRefreshToken(refreshToken);
        loginVO.setRefreshTokenExpiresIn(jwtProperties.getRefresTokenExpireIn());
        return loginVO;
    }

    @Override
    public void register(RegisterDTO dto) {
        //昵称默认和用户名一致
        if (StrUtil.isEmpty(dto.getNickName())){
            dto.setNickName(dto.getUserName());
        }
        User user = this.findUserByUserName(dto.getUserName());
        if (dto.getUserName().equals("")){
            throw new GlobalException("用户名包含敏感字符");
        }
        if (dto.getNickName().equals("")){
            throw new GlobalException("昵称包含敏感字符");
        }
        if (!Objects.isNull(user)){
            throw new GlobalException(ResultCode.USERNAME_ALREADY_REGISTER);
        }
        user = BeanUtils.copyProperties(dto, User.class);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        this.save(user);
        log.info("注册用户，用户Id：{}，用户名：{}，昵称：{}",user.getId(),dto.getUserName(),dto.getNickName());
    }

    @Override
    public void modifyPassword(ModifyPwdDTO dto) {
        UserSession session = SessionContext.getSession();
        User user = this.getById(session.getUserId());
        if (!dto.getOldPassword().equals(user.getPassword())){
            throw new GlobalException("旧密码不正确");
        }
        if (!passwordEncoder.matches(dto.getOldPassword(), user.getPassword())) {
            throw new GlobalException("旧密码不正确");
        }
        user.setPassword(passwordEncoder.encode(dto.getNewPassword()));
        this.updateById(user);
        log.info("用户修改密码，用户id:{},用户名：{}，昵称：{}",user.getId(),user.getUserName());
    }

    @Override
    public UserVO findUserById(Long id) {
        User user = this.getById(id);
        UserVO vo = BeanUtils.copyProperties(user, UserVO.class);
        vo.setOnline(imClient.isOnline(id));
        return vo;
    }

    @Override
    public List<OnlineTerminalVO> getOnlineTerminals(String userIds) {
        List<Long> userIdList = Arrays.stream(userIds.split(",")).map(Long::parseLong).collect(Collectors.toList());
        //查询在线的终端
        Map<Long,List<IMTerminalType>> terminalMap = imClient.getOnlineTerminal(userIdList);
        //组装vo
        List<OnlineTerminalVO> vos = new LinkedList<>();
        terminalMap.forEach((userId,types)->{
            List<Integer> terminals = types.stream().map(IMTerminalType::code).collect(Collectors.toList());
            vos.add(new OnlineTerminalVO(userId,terminals));
        });
        return vos;
    }

    @Override
    public User findUserByUserName(String userName) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>();
        queryWrapper.eq(User::getUserName, userName);
        return getOne(queryWrapper);
    }

    @Override
    public List<UserVO> findUserByName(String username) {
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(User::getUserName,username).or().like(User::getNickName,username).last("limit 20");
        List<User> users = this.list(queryWrapper);
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        List<Long> onlineUserIds = imClient.getOnlineUser(userIds);
        return users.stream().map(u ->{
            UserVO vo = BeanUtils.copyProperties(u, UserVO.class);
            vo.setOnline(onlineUserIds.contains(u.getId()));
            return vo;
        }).collect(Collectors.toList());
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(UserVO vo) {
        UserSession session = SessionContext.getSession();
        if (StrUtil.isEmpty(vo.getNickName())){
        //if(!vo.getNickName().equals(sensitiveFilterUtil.filter(vo.getNickName()))){
            throw new GlobalException("昵称包含敏感字符");
        }
        if (!session.getUserId().equals(vo.getId())){
            throw new GlobalException("不允许修改其他用户信息");
        }
        User user = this.getById(vo.getId());
        if (Objects.isNull(user)){
            throw new GlobalException("用户不存在");
        }
        //TODO

        //更新用户信息
        user.setNickName(vo.getNickName());
        user.setSex(vo.getSex());
        user.setSignature(vo.getSignature());
        user.setHeadImage(vo.getHeadImage());
        user.setHeadImageThumb(vo.getHeadImageThumb());
        this.updateById(user);
        log.info("用户信息更细,用户：{}",user);
    }
}
